﻿//     Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using Gateway.UpdateService.Models;

namespace Gateway.UpdateService.Manifests
{
    public class BlobDownloader 
    {
        public static async Task<HttpResponseMessage> BlobRequest(PackageManifest manifest, string packageName, string fileName, bool isHeadRequest, RangeHeaderValue requestBlobRange)
        {
            Trace.TraceInformation("Blob contents request [{0}][{1}][{2}]. Head: {3}. Range: {4}",
                manifest.Version, packageName, fileName, isHeadRequest,
                requestBlobRange == null ? "(None)" : String.Join(", ", requestBlobRange.Ranges
                    .Select(range => String.Format("{0}:{1}", range.From, range.To))));
            var blob = await StorageManifests.GetManifestFileBlobAsync(manifest, packageName, fileName);
            if (blob == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
            long blobLength = blob.Properties.Length;
            long from = 0;
            long to = blobLength - 1;
            bool isPartial = false;
            long contentLength = blobLength;
            if (requestBlobRange != null && requestBlobRange.Ranges.Count != 0)
            {
                if (requestBlobRange.Ranges.Count > 1)
                {
                    throw new HttpResponseException(HttpStatusCode.RequestedRangeNotSatisfiable);
                }
                var range = requestBlobRange.Ranges.First();
                from = range.From ?? 0;
                to = (!range.To.HasValue || range.To > blobLength - 1) ? blobLength - 1 : range.To.Value;
                if (from < 0 || to > blobLength - 1 || from > to)
                {
                    throw new HttpResponseException(HttpStatusCode.RequestedRangeNotSatisfiable);
                }
                isPartial = true;
                contentLength = to - from + 1;
            }
            var response = new HttpResponseMessage();
            if (isHeadRequest)
            {
                // Don't know if this is a MVC bug or not, but it seems that we need a non-empty content for the 
                // Content-Length header to be set correctly
                response.Content = new StringContent("0");
            }
            else if (isPartial)
            {
                var stream = new MemoryStream((int)contentLength);
                await blob.DownloadRangeToStreamAsync(stream, from, contentLength);
                stream.Position = 0;
                response.Content = new StreamContent(stream);
            }
            else
            {
                response.Content = new StreamContent(await blob.OpenReadAsync());
            }
            response.Headers.AcceptRanges.Add("bytes");
            response.StatusCode = isPartial ? HttpStatusCode.PartialContent : HttpStatusCode.OK;
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = fileName;
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(blob.Properties.ContentType);
            response.Content.Headers.ContentLength = contentLength;
            if (isPartial)
            {
                response.Content.Headers.ContentRange = new ContentRangeHeaderValue(from, to, blobLength);
            }
            return response;
        }
    }
}